/**
 * 组件拖拽缩放缩放功能
 */

import * as d3 from "d3";
import componentConfig from "../componentConfig";
import D3Selection from "./selection";

let canEdit = false;
let currentSelectedElements = new Set();
let currentHandlerInfo = new Map();
let keyboardMoveTimer = null;
let keyboardMoveInterval = 50;
let keyboardMoveAmount = 1;
let clipboard = null;                    // 剪贴板：用于存储复制的元素信息
const pasteOffset = 20;                  // 粘贴时的偏移量

let rotateInstance = null;  // 旋转实例
let snapInstance = null; // 吸附实例
let guidelineInstance = null; // 参考线实例

// 新增：跟踪是否正在拖拽，解决点击触发拖拽问题


// 开启编辑模式
export function dragResizeOpen(containerId) {
    canEdit = true;
    const container = d3.select(`#${containerId}`);
    // 绑定键盘事件
    window.addEventListener('keydown', handleKeyDown);
    window.addEventListener('keyup', handleKeyUp);

    // 点击画布空白处清除选中
    container.on("click", function (e) {
        if (!canEdit || isDragging) return; // 新增：拖拽时不处理点击
        if (e.target.tagName === "svg" || e.target === this) {
            clearSelection(d3);
        }
    });

    // 返回状态管理器以便外部访问
    return {
        container
    };
}

// 关闭编辑模式
export function dragResizeClose() {
    canEdit = false;
    clearSelection(d3);
    removeAllHandlers(d3);
    window.removeEventListener('keydown', handleKeyDown);
    window.removeEventListener('keyup', handleKeyUp);
    clearKeyboardMoveTimer();
    clipboard = null;
}

// 生成唯一标识
export function generateRandomKey(length = 18) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return Array(length).fill().map(() => chars[Math.floor(Math.random() * chars.length)]).join('');
}

/**
 * 初始化拖拽缩放功能
 * @param {Object} d3Instance d3实例
 * @param {Object} container SVG容器
 * @param {Object} selection 当前元素
 * @param {Object} config 配置参数
 */
export function dragResizeInit(d3Instance, container, selection, config, rotate, snap, guideline) {
    rotateInstance = rotate;
    snapInstance = snap;
    guidelineInstance = guideline;

    config = Object.assign(
        {
            x: selection.attr('x'),
            y: selection.attr('y'),
            minWidth: 20,
            minHeight: 20,
        },
        config
    );

    const randomKey = generateRandomKey();
    const handlerClass = `resize-handler-${randomKey}`;
    const groupClass = `drag-resize-group-${randomKey}`;
    const targetClass = `drag-resize-target-${randomKey}`;

    selection.datum({
        class: selection.attr('class') || '',
        handlerClass,
        groupClass,
        targetClass,
        originalConfig: {...config},
        selection: selection
    });

    initElement(selection, groupClass, handlerClass, targetClass);
    bindClickEvent(d3Instance, selection, container, handlerClass, targetClass, config);
    bindDragEvents(d3Instance, selection, container, groupClass, handlerClass, targetClass, config);

    clearSelection(d3);

    // 选中新元素
    selectElement(d3, selection.node(), handlerClass, config, container);
}

function initElement(selection, groupClass, handlerClass, targetClass) {
    selection
        .attr('class', `${selection.datum().class} ${groupClass} ${targetClass}`)
        .attr('drag-resize-group-name', groupClass)
        .attr('data-class-common-key', handlerClass);
}

function bindClickEvent(d3Instance, selection, container, handlerClass, targetClass, config) {
    selection.on('click', function (e) {
        if (!canEdit) return; // 新增：拖拽时不处理点击
        e.stopPropagation();

        const isCtrlPressed = e.ctrlKey || e.metaKey;
        const element = this;

        if (isCtrlPressed) {
            if (currentSelectedElements.has(element)) {
                deselectElement(d3Instance, element);
            } else {
                selectElement(d3Instance, element, handlerClass, config, container);
            }
        } else {
            clearSelection(d3Instance);
            selectElement(d3Instance, element, handlerClass, config, container);
        }

        drawAllHandlers(d3Instance, container);
    });
}

function bindDragEvents(d3Instance, selection, container, groupClass, handlerClass, targetClass, config) {
    selection.call(
        d3Instance.drag()
            .on('start', function (e) {
                if (!canEdit) return;
                const isCtrlPressed = e.ctrlKey || e.metaKey;
                const element = this;

                if (!isCtrlPressed && !currentSelectedElements.has(element)) {
                    clearSelection(d3Instance);
                    selectElement(d3Instance, element, handlerClass, config, container);
                }

                snapInstance.updateOffset(e, selection);

                drawAllHandlers(d3Instance, container);

            })
            .on('drag', function (e) {
                if (!canEdit) return;
                
                // 更新吸附状态
                if (currentSelectedElements.size === 1) {
                    // 获取吸附建议的位置
                    const position = snapInstance.updatePosition({selection, event: e});
                    
                    // 应用位置，允许继续拖动
                    updatePosition(d3Instance, selection, position.x, position.y);
                } else {
                    // 多元素拖动时，使用相对位移
                    const dx = e.dx;
                    const dy = e.dy;
                    currentSelectedElements.forEach(el => {
                        const elem = d3Instance.select(el);
                        const currX = +elem.attr('x');
                        const currY = +elem.attr('y');
                        updatePosition(d3Instance, elem, currX + dx, currY + dy);
                    });
                }
            })
            .on('end', function () {
                if (!canEdit) return;

                guidelineInstance.clear();
            })
    );
}

function updatePosition(d3Instance, elem, x, y) {

    elem.attr('x', x).attr('y', y);

    const pbj = currentHandlerInfo.get(elem.node());

    const {handlerClass: hc} = pbj;
    if (hc) {
        updateResizerPositions(d3Instance, hc, x, y, +elem.attr('width'), +elem.attr('height'));
    }
}


function getViewport(container) {
    return {
        left: 0,
        right: container.node()?.clientWidth,
        top: 0,
        bottom: container.node()?.clientHeight
    };
}

function selectElement(d3Instance, element, handlerClass, config, container) {
    const elem = d3Instance.select(element);
    elem.classed('elementActive', true);
    currentSelectedElements.add(element);
    currentHandlerInfo.set(element, {handlerClass, config});
    drawResizers(d3Instance, container, elem, handlerClass, config);
}

export function deselectElement(d3Instance, element) {
    const elem = d3Instance.select(element);
    elem.classed('elementActive', false);
    currentSelectedElements.delete(element);
    const {handlerClass} = currentHandlerInfo.get(element);
    currentHandlerInfo.delete(element);

    if (handlerClass) {
        d3Instance.selectAll(`.${handlerClass}`).remove();
    }
}

export function clearSelection(d3Instance = d3) {
    currentSelectedElements.forEach(element => {
        d3Instance.select(element).classed('elementActive', false);
        const {handlerClass} = currentHandlerInfo.get(element);
        if (handlerClass) {
            d3Instance.selectAll(`.${handlerClass}`).remove();
        }
    });
    currentSelectedElements.clear();
    currentHandlerInfo.clear();
    clearKeyboardMoveTimer();
}

function removeAllHandlers(d3Instance = d3) {
    currentHandlerInfo.forEach(({handlerClass}) => {
        d3Instance.selectAll(`.${handlerClass}`).remove();
    });
}

export function drawAllHandlers(d3Instance, container) {
    removeAllHandlers(d3Instance);
    currentSelectedElements.forEach(element => {
        const elem = d3Instance.select(element);
        const {handlerClass, config} = currentHandlerInfo.get(element);
        drawResizers(d3Instance, container, elem, handlerClass, config);
    });
}

function drawResizers(d3Instance, container, selection, handlerClass, config) {
    // 确保只有选中的元素才会绘制手柄
    if (!currentSelectedElements.has(selection.node())) {
        return;
    }

    d3Instance.selectAll(`.${handlerClass}`).remove();

    const size = 5;

    const x = +selection.attr('x');
    const y = +selection.attr('y');
    const width = +selection.attr('width');
    const height = +selection.attr('height');
    

    const handlers = [
        {pos: [x - size / 2, y - size / 2], class: 'rotate-point rotate-point-nw', cursor: 'nw-resize', direct: 0},
        {pos: [x + width - size / 2, y - size / 2], class: 'rotate-point rotate-point-ne', cursor: 'ne-resize', direct: 1},
        {pos: [x + width - size / 2, y + height - size / 2], class: 'rotate-point rotate-point-se', cursor: 'se-resize', direct: 2},
        {pos: [x - size / 2, y + height - size / 2], class: 'rotate-point rotate-point-sw', cursor: 'sw-resize', direct: 3},
        {pos: [x + width / 2 - size / 2, y - size / 2], cursor: 'n-resize', direct: 4},
        {pos: [x + width - size / 2, y + height / 2 - size / 2], cursor: 'e-resize', direct: 5},
        {pos: [x + width / 2 - size / 2, y + height - size / 2], cursor: 's-resize', direct: 6},
        {pos: [x - size / 2, y + height / 2 - size / 2], cursor: 'w-resize', direct: 7},
        {pos: [x + width + 16/2, y - 20], class: 'rotate-handle', cursor: 'crosshair', direct: 1, type: 'img', imgSrc:require('@/assets/rotate_cursor.png')},
    ];


    

    const parentNode = selection.node().parentNode;     
    const classList = parentNode.classList;
    const parent = d3Instance.select(`.${classList[0]}`);

    handlers.forEach((item, index) => {

        const className = (item.class ?? '') + ` resize-handle ${handlerClass}-${index} ${handlerClass}`;
        

        if (item.type === 'img') {
            parent.append('image')
                .attr('xlink:href', item.imgSrc)
                .attr('class', className)
                .attr('x', item.pos[0])
                .attr('y', item.pos[1])
                .attr('width', 16)
                .attr('height', 16)
                .style('cursor', item.cursor)
                .attr('data-resize-handler', handlerClass)
        } else {
            parent.append('rect')
                .attr('class', className)
                .attr('x', item.pos[0])
                .attr('y', item.pos[1])
                .attr('width', size)
                .attr('height', size)
                .attr('data-direct', item.direct)
                .attr('data-resize-handler', handlerClass)
                .style('cursor', item.cursor)
                .style('fill', '#fff')
                .style('stroke', '#4e6ef2')
                .style('stroke-width', '1px')
                .call(d3Instance.drag()
                    .on('drag', function (e) {
                        if (!canEdit) return;
                        const directionIndex = +d3Instance.select(this).attr('data-direct');
                        handleResize(e, directionIndex, selection, config, handlerClass, container);
                    })
                );
        }
    });

    // 进选中1个的时候绑定可以旋转
    if (currentSelectedElements?.size === 1) {
        rotateInstance.bindPointsEvents(selection);
    }
}

//缩放
function handleResize(e, directionIndex, selection, config, handlerClass, container) {
    if (!canEdit) return;
    const dx = e.dx, dy = e.dy;

    let newX = +selection.attr('x'), newY = +selection.attr('y');
    let newWidth = +selection.attr('width'), newHeight = +selection.attr('height');

    switch (directionIndex) {
        case 0:
            newX += dx;
            newWidth -= dx;
            newY += dy;
            newHeight -= dy;
            break;
        case 1:
            newWidth += dx;
            newY += dy;
            newHeight -= dy;
            break;
        case 2:
            newWidth += dx;
            newHeight += dy;
            break;
        case 3:
            newX += dx;
            newWidth -= dx;
            newHeight += dy;
            break;
        case 4:
            newY += dy;
            newHeight -= dy;
            break;
        case 5:
            newWidth += dx;
            break;
        case 6:
            newHeight += dy;
            break;
        case 7:
            newX += dx;
            newWidth -= dx;
            break;
    }

    newWidth = Math.max(newWidth, config.minWidth || 20);
    newHeight = Math.max(newHeight, config.minHeight || 20);

    const componentName = selection.attr('data-component-name');
    const component = componentConfig[componentName].component({width: newWidth, height: newHeight})

    selection.attr('x', newX).attr('y', newY).attr('width', newWidth).attr('height', newHeight).html(component);
    updateResizerPositions(d3, handlerClass, newX, newY, newWidth, newHeight);
}

function updateResizerPositions(d3Instance, handlerClass, x, y, width, height) {
    const size = 7;
    const positions = [
        {x: x - size / 2, y: y - size / 2},
        {x: x + width - size / 2, y: y - size / 2},
        {x: x + width - size / 2, y: y + height - size / 2},
        {x: x - size / 2, y: y + height - size / 2},
        {x: x + width / 2 - size / 2, y: y - size / 2},
        {x: x + width - size / 2, y: y + height / 2 - size / 2},
        {x: x + width / 2 - size / 2, y: y + height - size / 2},
        {x: x - size / 2, y: y + height / 2 - size / 2},
        {x: x + width + 16/2, y: y - 20}
    ];

    const handlers = d3Instance.selectAll(`[data-resize-handler="${handlerClass}"]`);
    if (handlers.size() === 0) return;

    handlers.each(function (_, i) {
        d3Instance.select(this)
            .attr('x', positions[i].x)
            .attr('y', positions[i].y);
    });
}

function handleKeyDown(e) {
    if (!canEdit) return;

    // 只有选中了元素才允许键盘控制
    if (currentSelectedElements.size === 0) return;
    const isMac = /Mac/.test(navigator.platform);
    const isCtrlOrCmd = isMac ? e.metaKey : e.ctrlKey;

    //复制功能：Ctrl/Cmd + C
    if (isCtrlOrCmd && e.key === 'c' && currentSelectedElements.size > 0) {
        e.preventDefault();

        clipboard = Array.from(currentSelectedElements).map(el => {
            const d3El = d3.select(el);
            let data = {
                tagName: el.tagName,
                x: +d3El.attr('x'),
                y: +d3El.attr('y'),
                width: +d3El.attr('width'),
                height: +d3El.attr('height'),
                fill: d3El.attr('fill'),
                stroke: d3El.attr('stroke'),
                strokeWidth: d3El.attr('stroke-width'),
                class: d3El.attr('class'), // 保存 class
                style: d3El.attr('style'), // 保存 style
                originalConfig: d3El.datum().originalConfig, // 保存原始配置
                contextMenuHandler: d3El.on('contextmenu'), // 保存右键事件处理函数
                imageUrl: d3El.attr('imageUrl')
            };

            // 如果是 image 元素，保存 href 属性
            if (el.tagName === 'image') {
                data.href = d3El.attr('href') || d3El.attr('xlink:href'); // 兼容旧版浏览器
            }

            return data;
        });

        console.log('已复制', clipboard.length, '个元素');
        return;
    }

    //粘贴功能：Ctrl/Cmd + V
    if (isCtrlOrCmd && e.key === 'v' && clipboard) {
        e.preventDefault();

        // 获取或定义粘贴所需的上下文信息
        const container = d3.select("svg"); // 假设容器是 SVG
        pasteElements(container);
        return;
    }

    // 删除功能：Delete 键
    if (e.key === 'Delete') {
        e.preventDefault();
        currentSelectedElements.forEach(element => {
            d3.select(element).remove();
            const {handlerClass} = currentHandlerInfo.get(element);
            if (handlerClass) {
                d3.selectAll(`.${handlerClass}`).remove();
            }
        });
        currentSelectedElements.clear();
        currentHandlerInfo.clear();
        return;
    }
    //方向键移动功能
    const allowedKeys = ['ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown'];
    if (allowedKeys.includes(e.key)) {
        e.preventDefault(); // 阻止浏览器默认滚动行为
        clearKeyboardMoveTimer();//清除之前的定时器
        keyboardMoveAmount = e.shiftKey ? 10 : 1;
        startKeyboardMove(e.key);
    }
}

// 新增一个粘贴函数，接收必要的上下文参数
export function pasteElements(container) {
    if (!clipboard) return;

    // 保留原选中元素
    const originalSelection = Array.from(currentSelectedElements);

    clipboard.forEach((data, index) => {
        const randomKey = generateRandomKey();
        const handlerClass = `resize-handler-${randomKey}`;
        const groupClass = `drag-resize-group-${randomKey}`;
        const targetClass = `drag-resize-target-${randomKey}`;

        const originalConfig = data.originalConfig || {};
        const config = {
            x: data.x + pasteOffset * (index + 1),
            y: data.y + pasteOffset * (index + 1),
            width: parseFloat(data.width) || 0,
            height: parseFloat(data.height) || 0,
            minWidth: originalConfig.minWidth || 20,
            minHeight: originalConfig.minHeight || 20,
        };

        let newEl;
        if (data.tagName === 'image') {
            newEl = container.append('image')
                .attr('href', data.href)
                .attr('xlink:href', data.href)
                .attr('preserveAspectRatio', 'none');
        } else {
            newEl = container.append(data.tagName);
        }

        newEl
            .attr('x', config.x)
            .attr('y', config.y)
            .attr('width', config.width)
            .attr('height', config.height)
            .attr('class', `${targetClass} ${groupClass}`)
            .attr('drag-resize-group-name', groupClass)
            .attr('data-class-common-key', handlerClass)
            .attr('imageUrl', data.imageUrl)
            .attr('id', generateRandomKey());


        newEl.datum({
            class: targetClass,
            handlerClass,
            groupClass,
            targetClass,
            originalConfig: config
        });
        // 为新元素添加右键事件
        if (data.contextMenuHandler) {
            newEl.on('contextmenu', data.contextMenuHandler);
        }
        bindClickEvent(d3, newEl, container, handlerClass, targetClass, config);
        bindDragEvents(d3, newEl, container, groupClass, handlerClass, targetClass, config);

        // 选中新元素
        selectElement(d3, newEl.node(), handlerClass, config, container);

    });

    // 刷新所有手柄
    drawAllHandlers(d3, container);
    console.log('粘贴完成，共', clipboard.length, '个元素');
}

function handleKeyUp(e) {
    if (!canEdit) return;
    const allowedKeys = ['ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown'];
    if (allowedKeys.includes(e.key)) {
        clearKeyboardMoveTimer();//松开按键时也清除
    }
}

function startKeyboardMove(direction) {
    keyboardMoveTimer = setInterval(() => {
        moveSelectedElements(d3, direction, keyboardMoveAmount);
    }, keyboardMoveInterval);
}

//移动
function moveSelectedElements(d3Instance, direction, amount) {
    // 确保我们有一个有效的容器来保存状态
    if (!d3Instance || !currentSelectedElements.size) return;

    // 获取当前选中元素的第一个元素所在的容器
    let container = null;
    currentSelectedElements.forEach(element => {
        if (!container) {
            container = d3Instance.select(element.parentNode);
        }
    });

    // 如果没有找到容器，尝试使用全局容器
    if (!container) {
        container = d3Instance.select("svg");
    }

    currentSelectedElements.forEach(element => {
        const elem = d3Instance.select(element);
        let x = +elem.attr('x');
        let y = +elem.attr('y');

        switch (direction) {
            case 'ArrowLeft':
                x -= amount;
                break;
            case 'ArrowRight':
                x += amount;
                break;
            case 'ArrowUp':
                y -= amount;
                break;
            case 'ArrowDown':
                y += amount;
                break;
        }

        elem.attr('x', x).attr('y', y);

        const {handlerClass} = currentHandlerInfo.get(element);
        if (handlerClass) {
            updateResizerPositions(d3Instance, handlerClass, x, y, +elem.attr('width'), +elem.attr('height'));
        }
    });
}

function clearKeyboardMoveTimer() {
    if (keyboardMoveTimer) {
        clearInterval(keyboardMoveTimer);
        keyboardMoveTimer = null;
    }
}

export function selectionInit(d3Instance, container, mouseObserver) {
    const selection = new D3Selection({
        svg: container,
        mouseObserver,
        selectComponent: (selection) =>{
            const randomKey = generateRandomKey();
            const handlerClass = `resize-handler-${randomKey}`;
            const groupClass = `drag-resize-group-${randomKey}`;
            const targetClass = `drag-resize-target-${randomKey}`;

            const config = {
                x: selection.attr('x'),
                y: selection.attr('y'),
                width: selection.width,
                height: selection.height,
                minWidth: 20,
                minHeight: 20,
            };

            
            selectElement(d3Instance, selection?.node(), handlerClass, config, container);
        },
        clearSelection: () => {
            clearSelection(d3Instance);
        }
    });

    return selection;
}